package com.zqs.compareface.utils.impl.threadpool;

import com.zqs.compareface.server.local.FaceImageContrast;
import com.zqs.compareface.utils.impl.ImageToBase64Util;
import com.zqs.compareface.utils.impl.LocalCheckUtil;
import com.zqs.compareface.utils.impl.MyLogUtil;
import com.zqs.compareface.utils.impl.threadpool.myLinkedBlockingQueue.ReWritedCapacityLinkedBlockingQueue;
import org.opencv.core.Mat;

import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @program: FaceCompares
 * @description: 自定义动态线程池
 *                自定义了一个核心线程数为 2，最大线程数为 5，线程存活时间为12秒，队列长度为 10 ReWritedCapacityLinkedBlockingQueue<>(10) 的线程池。
 *                然后给它塞 15 个耗时 10 秒的任务，直接让它 5 个最大线程都在工作，队列长度 10 个都塞满。
 *                当前的情况下，队列里面的 10 个，前 5 个在 10 秒后会被执行，后 5 个在 20 秒后会被执行。
 *                再加上最大线程数正在执行的 5 个，15 个任务全部执行完全需要 3 个 10 秒即 30 秒的时间。
 *                这个时候，如果我们把核心线程数和最大线程数都修改为 10。那么 10 个任务会直接被 10 个最大线程数接管，10 秒就会被处理完成。
 *                剩下的 5 个任务在队列里面，在 10 秒后被执行完成,所以，15 个任务执行完成需要 2 个 10 秒即 20 秒的时间处理完成了。
 *                <如果最小核心线程数和最大线程数的值，一个设置为1，另一个设置为10，那么调整的时候可能会出现核心线程数调整之后无效的情况。
 *                解决办法是：设置核心线程数的时候，同时设置最大线程数即可。可以把二者设置为相同的值；
 *                executor.setCorePoolSize(10);
 *                executor.setMaximumPoolSize(10);  >
 *
 *                核心线程数默认是不会被回收的，如果需要回收核心线程数，需要调用方法allowCoreThreadTimeOut 该值默认为 false
 *
 *                在使用submit()的时候一定要注意它的返回对象Future，为了避免任务执行异常被吞掉的问题，我们需要调用Future.get()方法。
 *                另外，使用execute()将不会出现这种问题
 * @author: ZQS
 * @create: 2021-08-14 01:00
 */
public class TheCustomDynamicThreadPoolUtil {
    public static void main(String[] args) throws InterruptedException {
        dynamicModifyExecutor();
    }
    /**
     * 自定义线程池
     */
    public static ThreadPoolExecutor buildThreadPoolExecutor(){
        return new ThreadPoolExecutor(4,
                4,
                4,
                TimeUnit.SECONDS,
                new ReWritedCapacityLinkedBlockingQueue<>(20),
                new NamedThreadFactory("我的线程"));

    }
    /**使用方法：
     * 提交任务给线程池，并修改线程池参数
     */
    public static void usedynamicModifyExecutor() throws InterruptedException{
        ThreadPoolExecutor executor = buildThreadPoolExecutor();
        //初始化参数开始================
        executor.setCorePoolSize(8);
        executor.setMaximumPoolSize(8);
        executor.prestartAllCoreThreads();
        ReWritedCapacityLinkedBlockingQueue reWritedCapacityLinkedBlockingQueue =
                (ReWritedCapacityLinkedBlockingQueue) executor.getQueue();
        reWritedCapacityLinkedBlockingQueue.setCapacity(50);
        //初始化参数结束================
        threadPoolStatus(executor,"线程池状态");
        Future future= executor.submit(() ->{
                threadPoolStatus(executor,"视频处理任务---");
                }
        );
        try {
            future.get();
        } catch (Exception e) {
            e.printStackTrace();
        }

        if (divide(executor.getActiveCount(),executor.getMaximumPoolSize()).equals("50%")){
            threadPoolStatus(executor,"改变之前");
            //根据读取配置文件或条件对线程池进行修改开始==================
            //最小核心线程数和最大线程数的值，设置为相同最佳
            executor.setCorePoolSize(10);
            executor.setMaximumPoolSize(10);
            executor.prestartAllCoreThreads();
            reWritedCapacityLinkedBlockingQueue.setCapacity(50);
            //根据读取配置文件或条件对线程池进行修改结束===================
            threadPoolStatus(executor,"改变之后");
            //有的任务不能合并线程，合并了就无法运行
//        Thread.currentThread().join();
        }
    }

    /**测试方法：
     * 提交任务给线程池，并修改线程池参数
     */
    private static void dynamicModifyExecutor() throws InterruptedException{
        ThreadPoolExecutor executor = buildThreadPoolExecutor();
        for (int i = 0; i < 15; i++) {
            executor.submit(() ->{
                threadPoolStatus(executor,"创建任务---");
                try {
                    TimeUnit.SECONDS.sleep(2);
                }catch (InterruptedException e){
                    e.printStackTrace();
                }
             }
            );
        }
        threadPoolStatus(executor,"改变之前");
        //最小核心线程数和最大线程数的值，设置为相同最佳
        executor.setCorePoolSize(10);
        executor.setMaximumPoolSize(10);
        executor.prestartAllCoreThreads();
        ReWritedCapacityLinkedBlockingQueue reWritedCapacityLinkedBlockingQueue =
                (ReWritedCapacityLinkedBlockingQueue) executor.getQueue();
        reWritedCapacityLinkedBlockingQueue.setCapacity(50);
        threadPoolStatus(executor,"改变之后");
        Thread.currentThread().join();
    }

    /**
     * 打印线程池状态
     */
    public static void threadPoolStatus(ThreadPoolExecutor executor, String name){
        ReWritedCapacityLinkedBlockingQueue reWritedCapacityLinkedBlockingQueue = (ReWritedCapacityLinkedBlockingQueue) executor.getQueue();
        System.out.println(Thread.currentThread().getName()+"-"+name+"-:"+
                " 核心线程数："+ executor.getCorePoolSize()+
                " 活动线程数："+ executor.getActiveCount()+
                " 最大线程数："+ executor.getMaximumPoolSize()+
                " 线程池活跃度："+divide(executor.getActiveCount(),executor.getMaximumPoolSize())+
                " 任务完成数："+ executor.getCompletedTaskCount()+
                " 队列大小："+ (reWritedCapacityLinkedBlockingQueue.size()+reWritedCapacityLinkedBlockingQueue.remainingCapacity())+
                " 当前排队线程数："+ reWritedCapacityLinkedBlockingQueue.size()+
                " 队列剩余大小："+ reWritedCapacityLinkedBlockingQueue.remainingCapacity()+
                " 队列使用度："+ divide(reWritedCapacityLinkedBlockingQueue.size(),reWritedCapacityLinkedBlockingQueue.size()+reWritedCapacityLinkedBlockingQueue.remainingCapacity()));
    }

    /**
     * 保留两位小数
     */
    public static String divide(int num1 ,int num2){
        return String.format("%1.2f%%",
                Double.parseDouble(num1+ "") / Double.parseDouble(num2+ "") * 100);
    }
}
